<?php
// +----------------------------------------------------------------------
// | 有理想的地方，地狱都是天堂。
// +----------------------------------------------------------------------
// | Copyright @ df81.com 版权所有
// +----------------------------------------------------------------------
// | 作者: 南国老符 邮箱：1062129401@qq.com
// +----------------------------------------------------------------------
use think\facade\Db;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use think\facade\Lang;

define("DS",DIRECTORY_SEPARATOR);

/**
 * 获取列表页URL
 */
function the_list_url($tabledir = 'product', $page = '', $lang = ''){
    echo get_list_url($tabledir, $page, $lang);
}

/**
 * 获取列表页URL
 */
function get_list_url($tabledir = 'product', $page = '', $lang = ''){
    if(empty($lang)) $lang = app('http')->getName();
    if($lang == 'city') $lang = 'cn';
    $moduleWhere[] = ['tabledir','=',$tabledir]; $moduleWhere[] = ['lang','=',$lang];
    $urlroute = Db::name('module')->where($moduleWhere)->value('urlroute');

    if(!empty($page)) $page = $page.'/';
    // 语言是否绑定二级域名
    if(!empty(config('global.url.bind_lang'))){
        $url = '/'.$urlroute.'/'.$page;
    }else{
        $url = '/'.$lang.'/'.$urlroute.'/'.$page;
    }
    
    return $url;
}

/**
 * 获取分类页URL
 * id 分类id
 * tabledir 分类所属数据表
 * page 页码
 */
function the_category_url($id = '', $tabledir = 'product', $page = '', $lang = ''){
    echo get_category_url($id, $tabledir, $page, $lang);
}

/**
 * 获取分类页URL
 * id 分类id
 * tabledir 分类所属数据表
 * page 页码
 */
function get_category_url($id = '', $tabledir = 'product', $page = '', $lang = ''){
    if(!empty($page)) $page = $page.'/';
    // 参数
    $url_category = config('global.url.category');
    if(empty($lang)) $lang = app('http')->getName();
    if($lang == 'city') $lang = 'cn';
    // 语言是否绑定二级域名
    $lang_pre = '';
    if(empty(config('global.url.bind_lang'))) $lang_pre = '/'.$lang;
    // 模型
    if(in_array($url_category,array(2,3))){
        $moduleWhere[] = ['tabledir','=',$tabledir]; $moduleWhere[] = ['lang','=',$lang];
        $module_urlroute = Db::name('module')->where($moduleWhere)->value('urlroute');
    }
    $urlroute = Db::name('sort')->where('id',$id)->value('urlroute');
    switch ($url_category) {
        case 0:
            return $lang_pre.'/'.$urlroute.'/'.$page;
            break;
        case 1:
            // 第一步：是否为顶级分类
            $sortRs = Db::name('sort')->where('urlroute',$urlroute)->field('id,parentid')->find();
            // 是顶级分类
            if($sortRs['parentid'] == 0){
                return $lang_pre.'/'.$urlroute.'/'.$page;
                break;
            }else{
                // 第二步：查找父级并返回
                return $lang_pre.'/'.getParentStr($sortRs['id'], 'sort', '/', 'id,parentid,urlroute', 'urlroute').'/'.$page;
                break;
            }
        case 2:
            return $lang_pre.'/'.$module_urlroute.'/'.$urlroute.'/'.$page;
            break;
        case 3:
            // 第一步：是否为顶级分类
            $sortRs = Db::name('sort')->where('urlroute',$urlroute)->field('id,parentid')->find();
            // 是顶级分类
            if($sortRs['parentid'] == 0){
                return $lang_pre.'/'.$module_urlroute.'/'.$urlroute.'/'.$page;
                break;
            }else{
                // 第二步：查找父级并返回
                return $lang_pre.'/'.$module_urlroute.'/'.getParentStr($sortRs['id'], 'sort', '/', 'id,parentid,urlroute', 'urlroute').'/'.$page;
                break;
            }
    }
}

/**
 * 获取详情页URL
 * id 信息id
 * tabledir 数据表
 */
function the_view_url($id = '', $tabledir = 'product', $lang = ''){
    echo get_view_url($id, $tabledir, $lang);
}

/**
 * 获取详情页URL
 * id 信息id
 * tabledir 数据表
 */
function get_view_url($id = '', $tabledir = 'product', $lang = ''){
    // 参数
    if(empty($lang)) $lang = app('http')->getName();
    if($lang == 'city') $lang = 'cn';
    // 语言是否绑定二级域名
    $lang_pre = '';
    if(empty(config('global.url.bind_lang'))) $lang_pre = '/'.$lang;
    
    $url_view = config('global.url.view'); $url_root = config('global.url.root');
    $url_root_module = config('global.url.root_module');
    /* 禁用：内容页置于根目录，或：启用但不是当前模型 */
    if($url_root == 0 or ($url_root == 1 and $url_root_module != $tabledir)){
        // 模型
        $moduleWhere[] = ['tabledir','=',$tabledir]; $moduleWhere[] = ['lang','=',$lang];
        $module_urlroute = Db::name('module')->where($moduleWhere)->value('urlroute');
        switch ($url_view) {
            case 0:
                $urlroute = Db::name($tabledir)->where('id',$id)->value('urlroute');
                return $lang_pre.'/'.$module_urlroute.'/'.$urlroute.'.html';
                break;
            case 1:
                return $lang_pre.'/'.$module_urlroute.'/'.$id.'.html';
                break;
        }
    }
    /* 启用：内容页置于根目录，且是当前模型*/
    if($url_root == 1 and $url_root_module == $tabledir){
        switch ($url_view) {
            case 0:
                $urlroute = Db::name($tabledir)->where('id',$id)->value('urlroute');
                return $lang_pre.'/'.$urlroute.'.html';
                break;
            case 1:
                return $lang_pre.'/'.$id.'.html';
                break;
        }
    }
}

/**四级嵌套循环：分类/关于我们/导航菜单等
* table 查询的表
* where 查询条件
* limit 数量控制
* order 排序
* module 模块表
* client 客户端
*/
function sublist($table = 'sort', $where = '', $limit = '0,1000', $order = 'sequence desc', $module = 'product', $client = ''){
    // 转为小写字母
    $general = new \common\General();
    $table = $general->capital_to_underline($table);
    
    // 基础查询
    $signWhere[] = ['signid','=',1];
    if(!empty($client)) $clientWhere = "find_in_set('$client',client)";
    $tableList = Db::name($table)->where($where)->where($signWhere)->where($clientWhere);
    
    /*城市分站 开始*/
    $cityid = Db::name('area')->where('bind_domain',request()->host(true))->value('id');
    if(!empty($cityid)) $tableList = $tableList->whereRaw("cityid = 0 or find_in_set($cityid,cityid)");
    /*城市分站 结束*/
    $tableList = $tableList->limit($limit)->order($order)->select();
    
    $paramArray = array($module,$table);
    $tableList = $tableList->each(function($item, $key) use ($paramArray){
        switch ($paramArray[1]){
            case 'navigation':
                // 城市分站替换首页url
                if($item['linkurl'] == '/' or strpos($item['linkurl'],'www.') !== false or strpos($item['linkurl'],'://'.request()->rootDomain()) !== false){
                    $item['linkurl'] = request()->domain();
                }
                break;
            case 'sort':
                // 追加链接地址
                $item['url'] = get_category_url($item['id'], $module);
                break;
        }
        return $item;
    });
    
    $tableList = $tableList->toArray();//一级
    foreach($tableList as $i=> $tableListRs){//二级
        $tableList[$i]['subOne'] = Db::name($table)->where('parentid','=',$tableListRs['id'])->where($signWhere)->where($clientWhere)
            ->order($order)->select()
            ->each(function($item, $key) use ($module){
                // 追加链接地址
                $item['url'] = get_category_url($item['id'], $module);
                return $item;
            })->toArray();
        foreach($tableList[$i]['subOne'] as $j=> $tableListRsRs){//三级
            $tableList[$i]['subOne'][$j]['subTwo'] = Db::name($table)->where('parentid','=',$tableListRsRs['id'])->where($signWhere)
                ->where($clientWhere)->order($order)->select()
                ->each(function($item, $key) use ($module){
                    // 追加链接地址
                    $item['url'] = get_category_url($item['id'], $module);
                    return $item;
                })->toArray();
            foreach($tableList[$i]['subOne'][$j]['subTwo'] as $k=> $fourRs){//四级
                $tableList[$i]['subOne'][$j]['subTwo'][$k]['subThree'] = Db::name($table)->where('parentid','=',$fourRs['id'])->where($signWhere)
                    ->where($clientWhere)->order($order)->select()
                    ->each(function($item, $key) use ($module){
                        // 追加链接地址
                        $item['url'] = get_category_url($item['id'], $module);
                        return $item;
                    })->toArray();
            }
        }
    }
    
    return $tableList;
}

/**中文获取星期几
 * 模板调用：{$rs.addtime|getWeek}
 * @date 时间戳
 * @lang 语言，cn中文，其他为英文
 */
function getWeek($date,$lang='cn'){
    $w = date('w',$date);
    if($lang = 'cn'){
        $week = array("0"=>"日","1"=>"一","2"=>"二","3"=>"三","4"=>"四","5"=>"五","6"=>"六"); 
    }else{
        $week = array("0"=>"Sun","1"=>"Mon","2"=>"Tue","3"=>"Wed","4"=>"Thur","5"=>"Fri","6"=>"Sat"); 
    }
    return $week[$w];
}

// unicode转汉字
function unicode2Chinese($str){
    return preg_replace_callback("#\\\u([0-9a-f]{4})#i",
        function ($r) {return iconv('UCS-2BE', 'UTF-8', pack('H4', $r[1]));},
        $str);
}

/**截取中文字符串
 * 模板调用：{$rs.title|msubstr=0,10}
*/
function msubstr($str, $start=0, $length, $suffix=true, $charset="utf-8"){
    if(function_exists("mb_substr")){
        $slice= mb_substr($str, $start, $length, $charset);
    }elseif(function_exists('iconv_substr')) {
        $slice= iconv_substr($str,$start,$length,$charset);
    }else{
        $re['utf-8'] = "/[x01-x7f]|[xc2-xdf][x80-xbf]|[xe0-xef][x80-xbf]{2}|[xf0-xff][x80-xbf]{3}/";
        $re['gb2312'] = "/[x01-x7f]|[xb0-xf7][xa0-xfe]/";
        $re['gbk'] = "/[x01-x7f]|[x81-xfe][x40-xfe]/";
        $re['big5'] = "/[x01-x7f]|[x81-xfe]([x40-x7e]|xa1-xfe])/";
        preg_match_all($re[$charset], $str, $match);
        $slice = join("",array_slice($match[0], $start, $length));
    }    
    $fix='';
    if(strlen($slice) < strlen($str)){
        $fix='...';
    }
    return $suffix ? $slice.$fix : $slice;
}

/*查找子类并转为一维数组
 * @function 调用的函数：f表示：父级->子级，c表示：子级->父级
 * @table 表名
 * @field 查询的字段
 * @pid 查询条件：id或parentid
 * @rid 取出的字段
 * @type 返回一维数组还是字符串，arr数组，str字符串
*/
function getOneArr($function,$table,$field,$pid,$rid,$str='str'){
    $temp = $function(Db::name($table)->field($field)->select(),$pid);
    $oneArr = array_column($temp,$rid);
    if($str == 'arr') return $oneArr;
    $strRs = "'".$pid."'";
    foreach ($oneArr as $value) {
    	$strRs .= ",'".$value."'";
    }
    return $strRs;
}

//无限级别分类（父级->子级）
function getChildSort($data,$parentid=0,$html="|---",$level=0){
	$temp = array();
	foreach ($data as $k => $v) {
		if($v['parentid'] == $parentid){
			$str = str_repeat($html, $level);
			$v['html'] = $str;
			$temp[] = $v;
			$temp = array_merge($temp,getChildSort($data,$v['id'],'|---',$level+1));
		}
	}
	return $temp;
}

/**
 * 无限级别分类（子级->父级），如：地区表，模板里获取父级标题
 * id 数据表id
 * table 数据表，如：area
 * html 连接字符串
 * field 查询字段
 * return_field 合并字段
 * 返回结果，如：海南省 东方市 八所镇
 */
function getParentStr($id, $table = 'area', $html = ' ', $field = 'id,parentid,title', $return_field = 'title'){
    $data = Db::name($table)->field($field)->select();
    $temp = array();
    foreach ($data as $k => $v) {
        if($v['id'] == $id){
            $temp[] = $v;
            $temp = array_merge(getParentSort($data,$v['parentid']),$temp);
        }
    }
    $temp = array_column($temp, $return_field);
    return implode($html, $temp);
}

//无限级别分类（子级->父级）
function getParentSort($data,$id,$html="|---",$level=0){
	$temp = array();
	foreach ($data as $k => $v) {
		if($v['id'] == $id){
			$str = str_repeat($html, $level);
			$v['html'] = $str;
			$temp[] = $v;
			$temp = array_merge(getParentSort($data,$v['parentid'],'|---',$level+1),$temp);
		}
	}
	return $temp;
}

/**获取文件大小，模板调用如：{$rs.size|getfilesize}
 * @param  number $size      字节数
 * @param  string $delimiter 数字和单位分隔符
 * @return string            格式化后的带单位的大小
 */
function getfilesize($size, $delimiter = '') {
    $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
    for ($i = 0; $size >= 1024 && $i < 5; $i++) $size /= 1024;
    return round($size, 2) . $delimiter . $units[$i];
}

/**多维数组查找值：目前只有前端模块（cn/en...）用到 - 20190518
* @value 查找的值
* @array 查找的数组
*/
function deep_in_array($value, $array) {
    foreach($array as $item){
        if(!is_array($item)){
            if($item == $value){
                return true;
            }else{
                continue;
            }
        }
        if(in_array($value, $item)){
            return true;
        }else if(deep_in_array($value, $item)){
            return true;
        }
    }
    return false;
}

//通用无限分类数组（父级->子级），如：地区
function getAreaArr($table,$id=0,$lang){
    $where['parentid']=$id;
    $where['lang']=$lang;
    $tableArr = Db::name($table)->field('title,id')->where($where)->order('sequence desc')->select();
    $arr = array(); 
    foreach ($tableArr as $k => $rs) {
        $rs[] = getAreaArr($table,$rs['id'],$lang);
        $arr[] = $rs; //组合数组
    } 
    return $arr;
}

/*判断模块表是否合法
@ table 数据表
@ lang 语言
@ 返回结果：true或false
*/
function isTable($table,$lang){
    //table必须是1-30位字母开头且由字母和下划线组成，lang必须是2-16为小写字母
    if(!preg_match('/^[a-zA-Z][a-zA-Z_]{0,29}$/',$table) or !preg_match('/^[a-z]{1,15}$/',$lang)) return false;
    //查找module表里是否存在table表
    $where[] = ['tabledir','=',$table]; $where[] = ['disabled','=',1]; $where[] = ['lang','=',$lang];
    $rs = Db::name('module')->field('id,tabledir')->where($where)->find();
    if(empty($rs)) return false;
    return true;
}

/*判断语言是否合法
@ lang 语言
@ 返回结果：true或false
*/
function isLang($lang){
    //lang必须是2-16为小写字母
    if(!preg_match('/^[a-z]{1,15}$/',$lang)) return false;
    //查找module表里是否存在table表
    $where[] = ['signid','=',1]; $where[] = ['mulu','=',$lang];
    $rs = Db::name('language')->field('id,mulu')->where($where)->find();
    if(empty($rs)) return false;
    return true;
}

/* 判断 文件/目录 是否可写（取代系统自带的 is_writeable 函数）
* file 文件/目录
* 返回true或false
*/
function isWritable($file){
    if(is_dir($file)){
        $dir = $file;
        if ($fp = @fopen("$dir/test.txt", 'w')) {
            @fclose($fp);
            @unlink("$dir/test.txt");
            $writeable = true;
        } else {
            $writeable = false;
        }
    } else {
        if ($fp = @fopen($file, 'a+')) {
            @fclose($fp);
            $writeable = true;
        } else {
            $writeable = false;
        }
    }
    return $writeable;
}

/**
 * 生成验签
 * userid 用户id
 * wx_unionid 微信unionid
 * qq_unionid QQ的unionid
 * is_admin 会员组类型：0前端会员1系统管理员2供应商3禁止访问9超级管理员（拥有全部权限）
 * type 用户类型：0个人，1组织
 */
function signToken($userid = null, $wx_unionid = null, $qq_unionid = null, $is_admin = null, $type = null){
    $key = md5(config('global.salt'));         //自定义的一个随机字串用户于加密中常用的 盐  salt
    $token = array(
        "iss" => $key,
        //"aud" => $id,//接收人，也就是发给谁
        "iat" => time(),//签发时间,当前时间
        "nbf" => time() + 10,//生效时间,在生成时间后一点点
        'exp' => time() + 86400,//过期时间，24小时
        'data'=> [
            'userid'=>$userid,
            'wx_unionid' => $wx_unionid,
            'qq_unionid' => $qq_unionid,
            'is_admin' => $is_admin,
            'type' => $type,
        ]//自定义信息
    );

    //  print_r($token);
    $jwt = JWT::encode($token, $key, "HS256");  //生成了 token
    return $jwt;
}

/**
 * 验证token
 * @param $token
 * @return array|int[]
 */
function checkToken($token, $lang = 'cn'){
    // 加载语言包
    Lang::load(app()->getAppPath().'lang'.DIRECTORY_SEPARATOR.$lang.'.php');
    // token验证为空！请重新登录
    if(empty($token)){
        $result['code'] = 9001;
        // $result['data']   = lang('token_empty');
        $result['data']   = lang('c_login_again');
        return $result;
    }
    $result["token"] = $token;
    $key = md5(config('global.salt'));     //自定义的一个随机字串用户于加密中常用的 盐  salt
    try {
        //延长有效期1分钟
        JWT::$leeway = 60;
        //对token解码，得到的一个对象，所以直接转成数组
        $data = (array)JWT::decode($token,new Key($key, 'HS256'));
        $result['data'] = $data['data'];
        $result['code'] = 9000;
        return $result;
        //如果验证失败，catch以下错误
    }catch (SignatureInvalidException $exception) {
        // token验证失败！请重新登录
        $result['code'] = 9002;
        // $result['data']   = lang('token_invalid');
        $result['data']   = lang('c_login_again');
        return $result;
    }catch (BeforeValidException $exception) {
        // token未生效，请稍后！
        $result['code'] = 9003;
        // $result['data'] = lang('token_valid');
        $result['data']   = lang('c_login_again');
        return $result;
    }catch (ExpiredException $exception) {
        // token已过期，请重新登录
        $result['code'] = 9004;
        // $result['data'] = lang('token_expired');
        $result['data']   = lang('c_login_again');
        return $result;
    }catch (Exception $exception) {
        // 未知错误，请重新登录
        $result['code'] = 9005;
        // $result['data'] = lang('token_error');
        $result['data']   = lang('c_login_again');
        return $result;
    }
}